#include "thread_pool.h"
#include "virtual_file.h"

#define CONVERSION_NUM 1024

void putsCommand(task_t * task) {
    printf("execute puts command.\n");
    train_t t;
    bzero(&t, sizeof(t));
    char filename[20] = {0}; //filename文件名--filename
    off_t len = 0;           //filesize文件大小--len

    //接收文件名
    recv(task->peerfd, filename, sizeof(filename), 0);

    //接收hash值
    char hash_val[128] = {0};
    recv(task->peerfd, hash_val, sizeof(hash_val),0);

    //查global_file表是否存在
    int exist_flag = isExist_file(task->sp, hash_val);
    
    if(exist_flag == 0){          //表示不存在
        //给客户端回复0，正常传输
        t.len = sizeof(exist_flag);
        send(task->peerfd, &exist_flag, sizeof(exist_flag), 0);
        //开始puts
        strcpy(filename, task->data);
        printf("filname: %s\n", filename);
        int ret = recvn(task->peerfd, &len, sizeof(len));
        printf("filelen: %ld.\n", len);

        //打开文件
        int fd = open(filename, O_CREAT|O_RDWR, 0644);
        if(fd < 0) {
            perror("open"); return;
        }
        // @zg
        long size_in_mb = len / (CONVERSION_NUM * CONVERSION_NUM);
        // 如果文件大小大于100MB，则进行splice零拷贝接收
        if (size_in_mb > 100) {
            printf("large file is up...\n"); // 仅供调试
            int fds[2];
            pipe(fds); // 创建一条匿名管道，并使用零拷贝splice
            long send_size = 0;
            ret = 0;
            while (send_size < len) {
                ret = splice(task->peerfd, NULL, fds[1], NULL, 4096, SPLICE_F_MORE);
                splice(fds[0], NULL, fd, NULL, ret, SPLICE_F_MORE);
                send_size += ret;
            }
            close(fd);
            addEpollReadfd(task->epfd, task->peerfd);
            printf("large file is up done.\n");//仅供调试
        } else {
            // @zg 判断文件是否大于100MB, 若大于100MB则进行mmap零拷贝传输
            //if (size_in_mb > 100) {
            //    // 制造文件空洞
            //    ftruncate(fd, len);
            //    printf("large file recv over.\n");

            //    // 接收文件
            //    char* pMap = mmap(NULL, len, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
            //    ret = recvn(task->peerfd, pMap, len);
            //    if ( ret == 0 ) { return; }

            //    //接收完成
            //    printf("large file recv over.\n");
            //    munmap(pMap, len);
            //    close(fd);
            //    return;
            //}

            // 小文件处理流程
            // 接收并写入文件
            char buff[1000] = {0};
            off_t left = len;
            while(left > 0) {
                if(left < 1000) {
                    ret = recvn(task->peerfd, buff, left);
                } else {
                    ret = recvn(task->peerfd, buff, sizeof(buff));
                }
                if(ret < 0) {
                    break;
                }
                ret = write(fd, buff, ret);
                left -= ret;
            }
            close(fd);
        }
        //插入global_file
        insert_global_file(task->sp, hash_val, filename, len);

    }            
    
        int uid;           //当前用户id, 用作owner_id
        int path_id;       //当前目录的vfb_id，用作parent_id
        mkdir_get_dir_id(task->sp, task->name, &uid, &path_id);

        //判断virtual_file表中是否有这条文件记录
        printf("filename:%s\n", filename);
        exist_flag = isExist_virtual_file(task->sp, filename, path_id, uid, 'f');

        if(exist_flag == 1){
            //文件存在
            char sendline[128] = {0};
            sprintf(sendline, "%s上传成功(秒传)\n", filename);
            send(task->peerfd, sendline, strlen(sendline), 0);
            return;
        }
        char path[512] = {0};                                     //path 当前路径
        get_pwd(task->sp, path_id, uid, path);
        //文件类型--普通文件'f'

        //插入virtual_file
        printf("filename:%s\n", filename);
        insert_virtual_file(task->sp, path_id, filename, uid, hash_val, len, 'f', path);

        char sendline[128] = {0};
        sprintf(sendline, "%s上传成功\n", filename);
        send(task->peerfd, sendline, strlen(sendline), 0);
        //上传任务执行完毕之后，再加回来
        addEpollReadfd(task->epfd, task->peerfd);
}

